#include <func.h>

#define MMAP_SIZE (4096 * 10)

int main(int argc, char* argv[])
{
    // ./mmap_copy src dst
    if (argc != 3) {
        fprintf(stderr, "Usage: %s src dst\n", argv[0]);
        exit(1);
    }
    // 1. 打开文件
    int srcfd = open(argv[1], O_RDONLY);
    if (srcfd == -1) {
        perror("open()");
        exit(1);
    }

    int dstfd = open(argv[2], O_RDWR | O_CREAT | O_TRUNC, 0666); /* O_RDWR */
    if (dstfd == -1) {
        perror("open()");
        exit(2);
    }
    // 2. 调用 mmap 复制文件
    // 将 dst 设置成和 src 一样大
    struct stat statbuf;
    fstat(srcfd, &statbuf);
    long fsize = statbuf.st_size;

    ftruncate(dstfd, fsize); /* dst 文件里面的数据都是空字符 */
    // 调用 mmap 复制文件
    long offset = 0;         /* 已复制数据的大小 */
    while (offset < fsize) {
        int length = (fsize - offset) >= MMAP_SIZE ? 
            MMAP_SIZE : (fsize - offset);
        // 映射 src 
        void* addr1 = mmap(NULL, length, PROT_READ, MAP_PRIVATE, srcfd, offset);
        if (addr1 == MAP_FAILED) {
            perror("mmap()");
            exit(1);
        }
        // 映射 dst
        void* addr2 = mmap(NULL, length, PROT_READ | PROT_WRITE, MAP_SHARED, dstfd, offset);
        if (addr2 == MAP_FAILED) {
            perror("mmap()");
            exit(1);
        }
        // memcpy
        memcpy(addr2, addr1, length);
        // 解除映射
        munmap(addr1, length);
        munmap(addr2, length);
        // 更新 offset
        offset += length;
    } // offset == fsize
    
    // 3. 关闭文件
    close(srcfd);
    close(dstfd);
    return 0;
}

